#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h> 
#include <string.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <errno.h>
#include <math.h>


#include "structure.h"
#include "toolkit.h"
#include "config.h"
#include "./DEV/partition/buffermap.h"


extern struct database db; 



void update_func(char *buff, char *IP){
  if( strncmp(buff,"have ",5) != 0){
    fprintf(stderr,"ERROR receiving look respond\n");
    return;
  }
  int i=5;
  int j=0; 
  
  char key[32];
  for(j = 0 ; j<32 ; j++){
    if (buff[i] == ' '){
      fprintf(stderr,"ERROR non-complete message\n");
      return;
    }
    key[j] = buff[i];
    i++;
  }
  int file = get_file_by_key(key);
  if (file == -1){
    return;
  }
  
  buffermap buffmap;
  
  buffmap.size = ceil((double)db.tab_file[file].size/db.tab_file[file].piece_size);
  
  char *tmp = malloc(buffmap.size*sizeof(char)+1);
  
  buffmap.buffer = tmp;
  
  int k;
  
  for(k=0 ; k<buffmap.size ; k++){
    buffmap.buffer[k] = buff[i];
    i++;
  }
  buffmap.buffer[k] = '\0';
  long long map_long = buffmap_to_int(buffmap);
  
  struct client *cp = db.tab_file[file].clients;
  while(cp != NULL) {
    if (strcmp(IP,cp->IP) == 0)
      break;
    cp = cp->next;
  }
  cp->client_buffer_map = map_long;
  printf("%s\n",buff);
  free(tmp); 
}




void update_request(){
  int i;
  char buffer[500];
  
  for (i=0 ; i<db.nb_file ; i++){
    if (db.tab_file[i].type == LEECH){
      struct client *cp=db.tab_file[i].clients;
      while(cp != NULL){
	bzero(buffer,500);
	args_bis* arglist = malloc(sizeof(args));
	
	arglist->portno = cp->port;
	arglist->IP = cp->IP;
	strcat(buffer,"have ");
	strncat(buffer,db.tab_file[i].key,32);
	
	buffermap buffermap = create_buffermap(db.tab_file[i].buffer_map, db.tab_file[i].size);
	
	strcat(buffer," ");
	strcat(buffer,buffermap.buffer);
	arglist->buffer = buffer;
	arglist->func = update_func;
	
	pthread_t Thread_connection;
	if (pthread_create(&Thread_connection,NULL,(void*)send_msg_bis,arglist) !=0)
	  fprintf(stderr,"ERROR creating thread.\n");
	cp=cp->next;
      }   
    }
  }
}


void update_tracker(){
  int i;
  char seed[5000];
  char leech[5000];
  char buff[10000];
  bzero(seed,5000);
  bzero(leech,5000);
  bzero(buff,10000);
  for (i=0 ; i<db.nb_file ; i++){
    if (db.tab_file[i].type == SEED){
      strncat(seed,db.tab_file[i].key,32);
      strcat(seed," ");
    }
    else if (db.tab_file[i].type == LEECH){
      strncat(leech,db.tab_file[i].key,32);
      strcat(leech," ");
    }
  }
  strcat(buff,"update seed [ ");
  strcat(buff,seed);
  strcat(buff,"] leech [ ");
  strcat(buff,leech);
  strcat(buff,"]");
  
  args* arglist = malloc(sizeof(args));
  arglist->argv = 0;
  arglist->portno = NO_PORT_TRACKER;
  arglist->IP = IP_TRACKER;
  arglist->buffer = buff;
  arglist->func = print;

  pthread_t Thread_connection;
  if (pthread_create(&Thread_connection,NULL,(void*)send_msg,arglist) !=0)
    fprintf(stderr,"ERROR creating thread.\n");
  if (pthread_join(Thread_connection, NULL) != 0)
    fprintf(stderr,"ERROR executing thread.\n");
}

void update(){
  while(1){
    sleep(UPDATE_TIME);
    printf("Update.\n");
    pthread_t update_peer;
    pthread_t update__tracker;
    if (pthread_create(&update_peer,NULL,(void*)update_request,NULL) !=0)
	 fprintf(stderr,"ERROR creating thread.\n");
    if (pthread_create(&update__tracker,NULL,(void*)update_tracker,NULL) !=0)
      fprintf(stderr,"ERROR creating thread.\n");
  }
}




